#define _BOUNDARY_ 100
#define _ITERATIONS_ 100000000
#define _TEAM_A_ 1
#define _TEAM_B_ 2

#include <cassert>
#include <iostream>
#include <cmath>
#include <cstdlib>
using namespace std;

// These are *NEVER* read by
// the opponent's strategy.
float move_team_a_X, move_team_a_Y, move_team_a_Z;
float move_team_b_X, move_team_b_Y, move_team_b_Z;
float shoot_team_a_X, shoot_team_a_Y, shoot_team_a_Z;
float shoot_team_b_X, shoot_team_b_Y, shoot_team_b_Z;
float lMS_team_a, lMS_team_b; // Last move's scores.
float score_team_a, score_team_b; // Cumulative scores.

// We take the initial “previous” move
// (also the initial current position)
// as the origin (0,0,0) by convention.
float lastPos_a_x, lastPos_a_y, lastPos_a_z;
float lastPos_b_x, lastPos_b_y, lastPos_b_z;

// Number of completed rounds (and
// *NOT* the current round number).
int iteration;

// Temporarily, effective move/shot is the
// same as intended move/shot. REMEMBER TO
// VARY THESE TO TRY OUT DIFFERENT REGIONS
// "TERRAINS"/ETC.. and finally leave them
// as mere declarations for the "e_xternal"
// rules-enforcing code to be tried out...
inline int effective_move_x( const float& x_new, const float& x, const float& y_new,
		const float& y, const float& z_new, const float& z )
	{ return x_new; }
inline int effective_move_y( const float& x_new, const float& x, const float& y_new,
		const float& y, const float& z_new, const float& z )
	{ return y_new; }
inline int effective_move_z( const float& x_new, const float& x, const float& y_new,
		const float& y, const float& z_new, const float& z )
	{ return z_new; }
inline int effective_shoot_x( const float& x, const float& y, const float& z )
	{ return x; }
inline int effective_shoot_y( const float& x, const float& y, const float& z )
	{ return y; }
inline int effective_shoot_z( const float& x, const float& y, const float& z )
	{ return z; }

void strategy_team_a(){

		/* Primitive strategy in which the opponent arbitrates in
		 * every turn. We have kept it like this as we should (in
		 * principle) be able to handle such a team too:
		 */
		move_team_a_X = ( rand() % 10001 )/100;
		move_team_a_Y = ( rand() % 10001 )/100;
		move_team_a_Z = ( rand() % 10001 )/100;
		shoot_team_a_X = ( rand() % 10001 )/100;
		shoot_team_a_Y = ( rand() % 10001 )/100;
		shoot_team_a_Z = ( rand() % 10001 )/100;
		// Primitive strategy code complete!

}

void strategy_team_b(){

	// We build the whole record ("log") first.
	// Currently, "iteration" will be the number
	// (starting from 1) of the previous round
	// (else 0 to indicate start of the game).

	// Record of oppenent's position
	// (obviously after the last round).

	static float actual_moves_a_x[ _ITERATIONS_ ];
	static float actual_moves_a_y[ _ITERATIONS_ ];
	static float actual_moves_a_z[ _ITERATIONS_ ];
	actual_moves_a_x[ iteration ] = lastPos_a_x;
	actual_moves_a_y[ iteration ] = lastPos_a_y;
	actual_moves_a_z[ iteration ] = lastPos_a_z;

	// Record of "our" agent's position
	// (obviously after the last round).

	static float actual_moves_b_x[ _ITERATIONS_ ];
	static float actual_moves_b_y[ _ITERATIONS_ ];
	static float actual_moves_b_z[ _ITERATIONS_ ];
	actual_moves_b_x[ iteration ] = lastPos_b_x;
	actual_moves_b_y[ iteration ] = lastPos_b_y;
	actual_moves_b_z[ iteration ] = lastPos_b_z;

	static float actual_shots_b_x[ _ITERATIONS_ ];
	static float actual_shots_b_y[ _ITERATIONS_ ];
	static float actual_shots_b_z[ _ITERATIONS_ ];
	actual_shots_b_x[ iteration ] = shoot_team_b_X;
	actual_shots_b_y[ iteration ] = shoot_team_b_Y;
	actual_shots_b_z[ iteration ] = shoot_team_b_Z;

	// Will do only for a relatively
	// small number of ITERATIONS
	// due to memory concerns?

	// Record of "our" team's score
	// (after playing the last round).

	static float score_b[ _ITERATIONS_+1 ];
	score_b[ iteration ] = lMS_team_b;

	static float attempted_moves_b_x[ _ITERATIONS_ ];
	static float attempted_moves_b_y[ _ITERATIONS_ ];
	static float attempted_moves_b_z[ _ITERATIONS_ ];

	static float attempted_shots_b_x[ _ITERATIONS_ ];
	static float attempted_shots_b_y[ _ITERATIONS_ ];
	static float attempted_shots_b_z[ _ITERATIONS_ ];

	// First few moves are hardcoded. REMEMBER
	// TO EXPLORE OPTIONS GUESSED IN THE DOC...
	if( iteration < 100 ){

		move_team_b_X = ( rand() % 10001 )/100;
		move_team_b_Y = ( rand() % 10001 )/100;
		move_team_b_Z = ( rand() % 10001 )/100;

		shoot_team_b_X = lastPos_a_x; // OR
		//shoot_team_b_X = ( rand() % 10001 )/100;
		shoot_team_b_Y = lastPos_a_y; // OR
		//shoot_team_b_Y = ( rand() % 10001 )/100;
		shoot_team_b_Z = lastPos_a_z; // OR
		//shoot_team_b_Z = ( rand() % 10001 )/100;

	}
	else{

		float c_x[13], c_y[13], c_z[13];
		float d_x[13], d_y[13], d_z[13];
		float e_x[13], e_y[13], e_z[13];

		// "their next predicted location"

		float diff_x = lastPos_a_x - lastPos_b_x;
		float diff_y = lastPos_a_y - lastPos_b_y;
		float diff_z = lastPos_a_z - lastPos_b_z;
		float squared_diff_x = pow( diff_x, 2 );
		float squared_diff_y = pow( diff_y, 2 );
		float squared_diff_z = pow( diff_z, 2 );

		float predicted_move_a_x =
			c_x[0] + c_x[4] * diff_x + c_x[5] * diff_y + c_x[6] * diff_z
			+ c_x[1] * squared_diff_x + c_x[2] * squared_diff_y + c_x[3] * squared_diff_z
			+ c_x[7] * lastPos_b_x + c_x[8] * lastPos_b_y + c_x[9] * lastPos_b_z
			+ c_x[10] * lastPos_a_x + c_x[11] * lastPos_a_y + c_x[12] * lastPos_a_z;
		float predicted_move_a_y =
			c_y[0] + c_y[4] * diff_x + c_y[5] * diff_y + c_y[6] * diff_z
			+ c_y[1] * squared_diff_x + c_y[2] * squared_diff_y + c_y[3] * squared_diff_z
			+ c_y[7] * lastPos_b_x + c_y[8] * lastPos_b_y + c_y[9] * lastPos_b_z
			+ c_y[10] * lastPos_a_x + c_y[11] * lastPos_a_y + c_y[12] * lastPos_a_z;
		float predicted_move_a_z =
			c_z[0] + c_z[4] * diff_x + c_z[5] * diff_y + c_z[6] * diff_z
			+ c_z[1] * squared_diff_x + c_z[2] * squared_diff_y + c_z[3] * squared_diff_z
			+ c_z[7] * lastPos_b_x + c_z[8] * lastPos_b_y + c_z[9] * lastPos_b_z
			+ c_z[10] * lastPos_a_x + c_z[11] * lastPos_a_y + c_z[12] * lastPos_a_z;

		// "where we attempt to move"

		diff_x = lastPos_b_x - predicted_move_a_x;
		diff_y = lastPos_b_y - predicted_move_a_y;
		diff_z = lastPos_b_z - predicted_move_a_z;
		squared_diff_x = pow( diff_x, 2 );
		squared_diff_y = pow( diff_y, 2 );
		squared_diff_z = pow( diff_z, 2 );

		float attempted_move_b_x =
			d_x[0] + d_x[4] * diff_x + d_x[5] * diff_y + d_x[6] * diff_z
			+ d_x[1] * squared_diff_x + d_x[2] * squared_diff_y + d_x[3] * squared_diff_z
			+ d_x[7] * lastPos_b_x + d_x[8] * lastPos_b_y + d_x[9] * lastPos_b_z
			+ d_x[10] * predicted_move_a_x + d_x[11] * predicted_move_a_y + d_x[12] * predicted_move_a_z;
		float attempted_move_b_y =
			d_y[0] + d_y[4] * diff_x + d_y[5] * diff_y + d_y[6] * diff_z
			+ d_y[1] * squared_diff_x + d_y[2] * squared_diff_y + d_y[3] * squared_diff_z
			+ d_y[7] * lastPos_b_x + d_y[8] * lastPos_b_y + d_y[9] * lastPos_b_z
			+ d_y[10] * predicted_move_a_x + d_y[11] * predicted_move_a_y + d_y[12] * predicted_move_a_z;
		float attempted_move_b_z =
			d_z[0] + d_z[4] * diff_x + d_z[5] * diff_y + d_z[6] * diff_z
			+ d_z[1] * squared_diff_x + d_z[2] * squared_diff_y + d_z[3] * squared_diff_z
			+ d_z[7] * lastPos_b_x + d_z[8] * lastPos_b_y + d_z[9] * lastPos_b_z
			+ d_z[10] * predicted_move_a_x + d_z[11] * predicted_move_a_y + d_z[12] * predicted_move_a_z;

		// "where we attempt to shoot"

		diff_x = attempted_move_b_x - predicted_move_a_x;
		diff_y = attempted_move_b_y - predicted_move_a_y;
		diff_z = attempted_move_b_z - predicted_move_a_z;
		squared_diff_x = pow( diff_x, 2 );
		squared_diff_y = pow( diff_y, 2 );
		squared_diff_z = pow( diff_z, 2 );

		float attempted_shot_b_x =
			e_x[0] + e_x[4] * diff_x + e_x[5] * diff_y + e_x[6] * diff_z
			+ e_x[1] * squared_diff_x + e_x[2] * squared_diff_y + e_x[3] * squared_diff_z
			+ e_x[7] * attempted_move_b_x + e_x[8] * attempted_move_b_y + e_x[9] * attempted_move_b_z
			+ e_x[10] * predicted_move_a_x + e_x[11] * predicted_move_a_y + e_x[12] * predicted_move_a_z;
		float attempted_shot_b_y =
			e_y[0] + e_y[4] * diff_x + e_y[5] * diff_y + e_y[6] * diff_z
			+ e_y[1] * squared_diff_x + e_y[2] * squared_diff_y + e_y[3] * squared_diff_z
			+ e_y[7] * attempted_move_b_x + e_y[8] * attempted_move_b_y + e_y[9] * attempted_move_b_z
			+ e_y[10] * predicted_move_a_x + e_y[11] * predicted_move_a_y + e_y[12] * predicted_move_a_z;
		float attempted_shot_b_z =
			e_z[0] + e_z[4] * diff_x + e_z[5] * diff_y + e_z[6] * diff_z
			+ e_z[1] * squared_diff_x + e_z[2] * squared_diff_y + e_z[3] * squared_diff_z
			+ e_z[7] * attempted_move_b_x + e_z[8] * attempted_move_b_y + e_z[9] * attempted_move_b_z
			+ e_z[10] * predicted_move_a_x + e_z[11] * predicted_move_a_y + e_z[12] * predicted_move_a_z;

		// "our predicted score expression"

		float c, c11, c12, c21, c22, c31, c32, c41, c42;
		float d11, d12, d21, d22, d31, d32, d41, d42,
			d51, d52, d61, d62, d71, d72, d81, d82;

		float value1 = lastPos_b_x;
		float squared_value1 = pow( value1, 2 );
		float value2 = shoot_team_b_X;
		float squared_value2 = pow( value2, 2 );
		float value3 = attempted_moves_b_x[ iteration ];
		float squared_value3 = pow( value3, 2 );
		float value4 = attempted_shots_b_x[ iteration ];
		float squared_value4 = pow( value4, 2 );

		float diff1 = lastPos_b_x - actual_moves_b_x[ iteration - 1 ];
		float squared_diff1 = pow( diff1, 2 );
		float diff2 = lastPos_a_x - actual_moves_a_x[ iteration - 1 ];
		float squared_diff2 = pow( diff2, 2 );
		float diff3 = lastPos_b_x - shoot_team_b_X;
		float squared_diff3 = pow( diff3, 2 );
		float diff4 = value4 - shoot_team_b_X;
		float squared_diff4 = pow( diff4, 2 );
		float diff5 = value3 - lastPos_b_x;
		float squared_diff5 = pow( diff5, 2 );
		float diff6 = shoot_team_b_X - lastPos_a_x;
		float squared_diff6 = pow( diff6, 2 );
		float diff7 = lastPos_b_x - lastPos_a_x;
		float squared_diff7 = pow( diff7, 2 );
		float diff8 = lastPos_b_x - shoot_team_b_X;
		float squared_diff8 = pow( diff8, 2 );

		float predicted_score_b_x =
			c + c11 * value1 + c12 * squared_value1 + c21 * value2 + c22 * squared_value2
			+ c31 * value3 + c32 * squared_value3 + c41 * value4 + c42 * squared_value4
			+ d11 * diff1 + d12 * squared_diff1 + d21 * diff2 + d22 * squared_diff2
			+ d31 * diff3 + d32 * squared_diff3 + d41 * diff4 + d42 * squared_diff4
			+ d51 * diff5 + d52 * squared_diff5 + d61 * diff6 + d62 * squared_diff6
			+ d71 * diff7 + d72 * squared_diff7 + d81 * diff8 + d82 * squared_diff8;

		value1 = lastPos_b_y;
		squared_value1 = pow( value1, 2 );
		value2 = shoot_team_b_Y;
		squared_value2 = pow( value2, 2 );
		value3 = attempted_moves_b_y[ iteration ];
		squared_value3 = pow( value3, 2 );
		value4 = attempted_shots_b_y[ iteration ];
		squared_value4 = pow( value4, 2 );

		diff1 = lastPos_b_y - actual_moves_b_y[ iteration - 1 ];
		squared_diff1 = pow( diff1, 2 );
		diff2 = lastPos_a_y - actual_moves_a_y[ iteration - 1 ];
		squared_diff2 = pow( diff2, 2 );
		diff3 = lastPos_b_y - shoot_team_b_Y;
		squared_diff3 = pow( diff3, 2 );
		diff4 = value4 - shoot_team_b_Y;
		squared_diff4 = pow( diff4, 2 );
		diff5 = value3 - lastPos_b_y;
		squared_diff5 = pow( diff5, 2 );
		diff6 = shoot_team_b_Y - lastPos_a_y;
		squared_diff6 = pow( diff6, 2 );
		diff7 = lastPos_b_y - lastPos_a_y;
		squared_diff7 = pow( diff7, 2 );
		diff8 = lastPos_b_y - shoot_team_b_Y;
		squared_diff8 = pow( diff8, 2 );

		float predicted_score_b_y =
			c + c11 * value1 + c12 * squared_value1 + c21 * value2 + c22 * squared_value2
			+ c31 * value3 + c32 * squared_value3 + c41 * value4 + c42 * squared_value4
			+ d11 * diff1 + d12 * squared_diff1 + d21 * diff2 + d22 * squared_diff2
			+ d31 * diff3 + d32 * squared_diff3 + d41 * diff4 + d42 * squared_diff4
			+ d51 * diff5 + d52 * squared_diff5 + d61 * diff6 + d62 * squared_diff6
			+ d71 * diff7 + d72 * squared_diff7 + d81 * diff8 + d82 * squared_diff8;

		value1 = lastPos_b_z;
		squared_value1 = pow( value1, 2 );
		value2 = shoot_team_b_Z;
		squared_value2 = pow( value2, 2 );
		value3 = attempted_moves_b_z[ iteration ];
		squared_value3 = pow( value3, 2 );
		value4 = attempted_shots_b_z[ iteration ];
		squared_value4 = pow( value4, 2 );

		diff1 = lastPos_b_z - actual_moves_b_z[ iteration - 1 ];
		squared_diff1 = pow( diff1, 2 );
		diff2 = lastPos_a_z - actual_moves_a_z[ iteration - 1 ];
		squared_diff2 = pow( diff2, 2 );
		diff3 = lastPos_b_z - shoot_team_b_Z;
		squared_diff3 = pow( diff3, 2 );
		diff4 = value4 - shoot_team_b_Z;
		squared_diff4 = pow( diff4, 2 );
		diff5 = value3 - lastPos_b_z;
		squared_diff5 = pow( diff5, 2 );
		diff6 = shoot_team_b_Z - lastPos_a_z;
		squared_diff6 = pow( diff6, 2 );
		diff7 = lastPos_b_z - lastPos_a_z;
		squared_diff7 = pow( diff7, 2 );
		diff8 = lastPos_b_z - shoot_team_b_Z;
		squared_diff8 = pow( diff8, 2 );

		float predicted_score_b_z =
			c + c11 * value1 + c12 * squared_value1 + c21 * value2 + c22 * squared_value2
			+ c31 * value3 + c32 * squared_value3 + c41 * value4 + c42 * squared_value4
			+ d11 * diff1 + d12 * squared_diff1 + d21 * diff2 + d22 * squared_diff2
			+ d31 * diff3 + d32 * squared_diff3 + d41 * diff4 + d42 * squared_diff4
			+ d51 * diff5 + d52 * squared_diff5 + d61 * diff6 + d62 * squared_diff6
			+ d71 * diff7 + d72 * squared_diff7 + d81 * diff8 + d82 * squared_diff8;

	}

	// Record of this round's desired
	// moves (after "deciding" them).

	attempted_moves_b_x[ iteration+1 ] = move_team_b_X;
	attempted_moves_b_y[ iteration+1 ] = move_team_b_Y;
	attempted_moves_b_z[ iteration+1 ] = move_team_b_Z;

	attempted_shots_b_x[ iteration+1 ] = shoot_team_b_X;
	attempted_shots_b_y[ iteration+1 ] = shoot_team_b_Y;
	attempted_shots_b_z[ iteration+1 ] = shoot_team_b_Z;

}

int move( const int team, const float& x, const float& y, const float& z ){

	if( ( x < 0 or x > _BOUNDARY_ ) or
			( y < 0 or y > _BOUNDARY_ ) or
			( z < 0 or z > _BOUNDARY_ ) )
		cerr << x << ":" << y << ":" << z << endl;

	if( team == _TEAM_A_ ){

		// Modify Team A's score here.

		move_team_a_X = effective_move_x( x, lastPos_a_x, y, lastPos_a_y, z, lastPos_a_z );
		move_team_a_Y = effective_move_y( x, lastPos_a_x, y, lastPos_a_y, z, lastPos_a_z );
		move_team_a_Z = effective_move_z( x, lastPos_a_x, y, lastPos_a_y, z, lastPos_a_z );

		lastPos_a_x = move_team_a_X;
		lastPos_a_y = move_team_a_Y;
		lastPos_a_z = move_team_a_X;

	}
	else if( team == _TEAM_B_ ){

		// Modify Team B's score here.

		move_team_b_X = effective_move_x( x, lastPos_b_x, y, lastPos_b_y, z, lastPos_b_z );
		move_team_b_Y = effective_move_y( x, lastPos_b_x, y, lastPos_b_y, z, lastPos_b_z );
		move_team_b_Z = effective_move_z( x, lastPos_b_x, y, lastPos_b_y, z, lastPos_b_z );

		lastPos_b_x = move_team_b_X;
		lastPos_b_y = move_team_b_Y;
		lastPos_b_z = move_team_b_X;

	}
	else return 0;

	return 1;

}

int target( const int team, const float& x, const float& y, const float& z ){

	if( x == -1 and y == -1 and z == -1 ){

		if( team == _TEAM_A_ ){

			// Modify Team A's score here for no
			// shot, if required (we don't know!).

		}
		else if( team == _TEAM_B_ ){

			// Modify Team B's score here for no
			// shot, if required (we don't know!).

		}
		else assert( false );

		return 2;
	}

	if( ( x < 0 or x > _BOUNDARY_ ) or
			( y < 0 or y > _BOUNDARY_ ) or
			( z < 0 or z > _BOUNDARY_ ) )
		cerr << x << ":" << y << ":" << z << endl;

	if( team == _TEAM_A_ ){

		// Modify Team A's score here.

		shoot_team_a_X = effective_shoot_x( x, y, z );
		shoot_team_a_Y = effective_shoot_y( x, y, z );
		shoot_team_a_Z = effective_shoot_z( x, y, z );

	}
	else if( team == _TEAM_B_ ){

		// Modify Team B's score here.

		shoot_team_b_X = effective_shoot_x( x, y, z );
		shoot_team_b_Y = effective_shoot_y( x, y, z );
		shoot_team_b_Z = effective_shoot_z( x, y, z );

	}
	else return 0;

	return 1;

}

int main(){

	// Initializing the starting positions and scores of both teams.
	move_team_a_X = 0, move_team_a_Y = 0, move_team_a_Z = 0;
	move_team_b_X = 0, move_team_b_Y = 0, move_team_b_Z = 0;
	lMS_team_a = 0, lMS_team_b = 0;
	score_team_a = 0, score_team_b = 0;

	lastPos_a_x = 0, lastPos_a_y = 0, lastPos_a_z = 0;
	lastPos_b_x = 0, lastPos_b_y = 0, lastPos_b_z = 0;

	iteration = 0;
	for( int i = 0; i < _ITERATIONS_; i++ ){

		strategy_team_a();
		strategy_team_b();

		move( _TEAM_A_, move_team_a_X, move_team_a_Y, move_team_a_Z );
		move( _TEAM_B_, move_team_b_X, move_team_b_Y, move_team_b_Z );

		target( _TEAM_A_, shoot_team_a_X, shoot_team_a_Y, shoot_team_a_Z );
		target( _TEAM_B_, shoot_team_b_X, shoot_team_b_Y, shoot_team_b_Z );

		iteration++;
	}

	return 1;

}
